package com.flink.timewindow.window;

import com.flink.timewindow.bean.WaterSensor;
import com.flink.timewindow.function.WaterSensorMapFunction;
import org.apache.flink.api.common.functions.AggregateFunction;
import org.apache.flink.api.common.functions.ReduceFunction;
import org.apache.flink.streaming.api.datastream.KeyedStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.datastream.WindowedStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;

public class WindowAggregateDemo {
    public static void main(String[] args) throws Exception {
        //获取执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        env.setParallelism(1);
        //获取数据源
        SingleOutputStreamOperator<WaterSensor> sensorDS = env.socketTextStream("10.90.100.102", 8888)
                //数据处理
                //切分转换
                .map(new WaterSensorMapFunction());
        //分组
        KeyedStream<WaterSensor, String> sensorKS = sensorDS.keyBy(value -> value.getId());

        //窗口分配器
        WindowedStream<WaterSensor, String, TimeWindow> sensorWS = sensorKS.window(
                TumblingProcessingTimeWindows.of(Time.seconds(10))
        );



        //窗口函数： 增量聚合函数 Aggregate
        /**
         * ①属于本窗口的第一条数据来，创建窗口，创建累加器
         * ②增量聚合:来一条计算一条，调用一次add方法
         * ③窗口输出时调用一次getresult方法
         * ④输入、中间累加器、输出 类型可以不一样，非常灵活
         */
        SingleOutputStreamOperator<String> aggregate = sensorWS.aggregate(
                //泛型： 1：输入数据的类型  2：累加器的类型 ，存储的中间计算结果的类型 3：输出的类型
                new AggregateFunction<WaterSensor, Integer, String>() {
            @Override
            public Integer createAccumulator() {//创建累加器，即初始化累加器
                System.out.println("创建累加器");
                return 0;
            }

            @Override
            public Integer add(WaterSensor value, Integer accumulator) {//将输入的元素添加到累加器中，聚合逻辑
                System.out.println("调用add方法，value：" + value + " ,accumulator：" + accumulator);
                //初始化的数据与传入进来的水位值之和
                return accumulator + value.getVc();
            }

            @Override
            public String getResult(Integer accumulator) {//从累加器中提取聚合的输出结果即获取最终结果，窗口触发时输出
                System.out.println("调用getResult方法");
                return accumulator.toString();
            }

            @Override
            public Integer merge(Integer a, Integer b) {//合并两个累加器，并将合并后的状态作为一个累加器返回,但这只有会话窗口才会用到
                System.out.println("调用merge方法");

                return 0;
            }
        });
        //打印
        aggregate.print();
        //执行
        env.execute();
    }
}
